1 Instalação e setup inicial
Seja bem-vindo(a) ao tutorial do monitoraSom! Nessa primeira etapa, vamos fazer os downloads e instalações necessárias para o uso do monitoraSom.
1.1 1. Baixar e instalar o R.
- Verifique se já existe alguma versão instalada.
- Ao fazer uma nova instalação, dê preferência para a versão mais recente.
- link para download: https://cran.r-project.org/bin/windows/base/
1.2 2. Baixar e instalar o Rstudio.
- Após instalar o R, instale o Rstudio.
- Atenção: se houver mais de uma versão do R instalada, certifique-se qual está sendo usada ao abrir o Rstudio.
- link para download: https://posit.co/download/rstudio-desktop/
1.3 3. Instalar o Rtools (passo necessário apenas para usuários do Windows)
- Rtools é necessário para compilar pacotes do R que foram instalados a partir do GitHub.
- Verifique se já existe alguma versão instalada. Caso exista, verifique se é adequada ao projeto. Se não for, desinstale a versão existente.
- Neste momento, a versão mais recente é a 4.5.
- link para download: https://cran.r-project.org/bin/windows/Rtools/
1.4 4. Criar uma nova pasta para conter os arquivos usandos pelo monitoraSom.
Para usuários do Windows, recomendamos criar uma pasta para análises na raiz do sistema, e dentro dela uma pasta para este projeto, por exemplo, “C:/Meus Projetos/monitoraSom_tutorial”. Dessa forma o caminho para os arquivos será o mesmo mesmo que os arquivos sejam movidos para outro computador.
1.5 5. Instalar o devtools para poder instalar pacotes a partir do GitHub.
Esse comando deve ser executado no Rstudio após a instalação do Rtools.
install.packages("devtools")
1.6 6. Carregar o devtools para o ambiente de trabalho.
library(devtools)
1.7 7. Instalar o monitoraSom
- O monitoraSom depende de outros pacotes do R para funcionar adequadamente.
- Atenção 1: A isntalação poderá solicitar a confirmação de instalação das dependências. Recomendamos que seja feita a instalação ou atualização de todas as dependências respondendo ‘1’ (“All”).
- Atenção 2: Pode ser solictada também a resposta sobre instalação de pacotes de precisam de compilação. Nesse caso, responda ‘Yes’.
install_github("ConservaSom/monitoraSom", dependencies = TRUE)
1.8 8. Carregar o monitoraSom no ambiente de trabalho do R para testar a instalação.
library(monitoraSom)
library(dplyr)
library(ggplot2)
library(patchwork)
1.9 9. Salvar esse script no diretório de trabalho conforme descrito no passo 4.
Priorize salvar com um nome informativo e que mantenha a sequência de passos desse e dos tutoriais seguintes, por exemplo, “script_01_instalação.R”.
1.10 Checkpoint 01
Você instalou o monitoraSom e está pronto para começar a usar. Salve esse script no diretório de trabalho conforme descrito no passo 4.
1.11 10. Organizando o ambiente de trabalho.
Vamos seguir a partir deste ponto assumindo que o diretório de trabalho está organizado conforme descrito no passo 4 e que o código está salvo em um arquivo em formato de script ou notebook (Rmarkdown ou Quarto).
Vamos verificar e, se necessário, ajustar manualmente o diretório de trabalho da sessão atual.
getwd()
## [1] "/home/grosa/R_repos/2025_SimposioFisicaEcologia_OficinaSomR/monitoraSom"
Se o script estiver no diretório de trabalho correto, use o comando abaixo para definir o diretório automaticamente.
setwd(dirname(rstudioapi::getActiveDocumentContext()$path))
getwd() # Verificando se o diretório de trabalho foi definido corretamente
Se quiser definir manualmente o diretório de trabalho, use o comando abaixo.
project_path <- paste0(
"<coloque aqui o caminho para a pasta do projeto>", "/monitoraSom"
)
setwd(project_path)
getwd() # Verificando se o diretório de trabalho foi definido corretamente
1.12 11. Povoando o diretório de trabalho com os arquivos de exemplo do monitoraSom.
Use a função set_workspace para adicionar os arquivos de
exemplo do monitoraSom ao seu diretório de trabalho. Esse comando é
recomendado para novos projetos. Evite executá-lo em diretórios que já
contenham dados de projetos em andamento. Isso poderá resultar em perdas
permanentes de dados.
set_workspace(project_path = "./", example_data = TRUE)
1.13 12. (Opcional) Limpeza de arquivos pre-carregados
Vamos apagar os arquivos de exemplo para continuar o tutorial como um novo projeto. Pule esta etapa se quiser obter os mesmos resultados do exemplo original.
file.remove(list.files("./detections/", full.names = TRUE))
file.remove(list.files("./match_grid_metadata/", full.names = TRUE))
file.remove(list.files("./match_scores/", full.names = TRUE))
file.remove(list.files("./soundscapes_metadata/", full.names = TRUE))
file.remove(list.files("./templates/", full.names = TRUE))
file.remove(list.files("./templates_metadata/", full.names = TRUE))
file.remove(list.files("./validation_outputs/", full.names = TRUE))
1.14 Checkpoint 02
Você povoou o diretório de trabalho com os arquivos de exemplo do monitoraSom e está pronto para seguir com o uso do pacote. Apague os arquivos de exemplo se quiser começar um novo projeto.
1.15 13. Usar o app de segmentação para escolher os templates.
Agora vamos usar o app de segmentação para escolher os templates. Note que como estamos somente escolhendo os templates, definimos o destino dos cortes de audio para a pasta “./templates”. Os templates são as amostras de som que desejamos usar para detecção nos passos seguintes. Podemos exportar os templates manualmente de dentro do app, mas nesse tutorial vamos usar o app somente para demarcar as ROIs, para depois exportar os cortes de audio automaticamente (ver passo 16).
No exemplo abaixo temos os arquivos de ROIs já feitos para este exemplo, mas vamos fazer um novo template contendo um canto completo e adicionar o comentário “Complete Song” para identificá-lo.
launch_segmentation_app(
user = "User", # Nome do usuário
project_path = "./", # Caminho para a pasta do projeto
preset_path = "./app_presets/", # Caminho para a pasta de presets
soundscapes_path = "./recordings/", # Caminho onde ler as gravações
roi_tables_path = "./roi_tables/", # Caminho para onde exportar as ROIs
cuts_path = "./templates/", # Caminho para onde exportar cortes de audio
dyn_range = c(-102, -42), # Ajuste do contraste do espectrograma
wl = 1024, # Ajuste do comprimento da janela do fft (parametro espectral)
ovlp = 50, # Ajuste da sobreposição do fft (parametro espectral)
color_scale = "greyscale 1", # Ajuste da escala de cores do espectrograma
nav_autosave = TRUE # Auomtação de salvamento ao trocar de soundscape
)
1.16 14. Usar o app de segmentação para segmentar as soundscapes.
Agora vamos usar o app de segmentação para segmentar as soundscapes. Nessa etapa, definimos o destino dos cortes de audio para a pasta “./roi_cuts”. As tabelas de ROIs que serão produzidas nessa etapa serão usadas para avaliar as detecções e medir a poerformance de cada template. Note que como a segmentação já está completa, não será necessário marcar novas ROIs nessa etapa.
launch_segmentation_app(
user = "User", project_path = "./", preset_path = "./app_presets/",
soundscapes_path = "./soundscapes/", roi_tables_path = "./roi_tables/",
dyn_range = c(-102, -42), wl = 1024, ovlp = 50,
color_scale = "greyscale 1", visible_bp = TRUE, nav_autosave = TRUE
)
1.17 15. Preparando os templates.
Vamos importar todas as tabelas de ROIs para verificarmos se temos o que precisamos. Note que as tabelas de ROIs das soundscapes e dos templates encontram-se na mesma pasta, mas podemos discriminá-las facilmentepelo nome do arquivo.
df_rois <- fetch_rois(rois_path = "./roi_tables/")
unique(df_rois$soundscape_file) # Verificando os nomes das gravações
## [1] "Bcu_1.wav" "Bcu_2.wav"
## [3] "W54393S25597_20201104_170000.wav" "W54431S25613_20191102_055000.wav"
## [5] "W54431S25613_20191102_064000.wav" "W54431S25613_20191104_154000.wav"
## [7] "W54431S25613_20191105_060000.wav" "W54443S25620_20191105_054000.wav"
## [9] "W54448S25622_20191101_073000.wav" "W54448S25622_20191101_125000.wav"
## [11] "W54448S25622_20191102_070000.wav" "W54448S25622_20191103_055000.wav"
## [13] "W54448S25622_20191104_171000.wav" "W54448S25623_20191102_064000.wav"
Filtrando as tabelas de ROIs para manter somente aquelas com os templates.
df_templates <- df_rois %>%
filter(roi_comment %in% c("Substructure C", "Complete Song")) %>%
group_by(roi_comment) %>%
sample_n(1)
glimpse(df_templates)
## Rows: 2
## Columns: 19
## Groups: roi_comment [2]
## $ soundscape_path <chr> "./recordings/Bcu_1.wav", "./recordings/Bcu_1.wav"
## $ soundscape_file <chr> "Bcu_1.wav", "Bcu_1.wav"
## $ roi_path <chr> "/home/grosa/R_repos/2025_SimposioFisicaEcologia_…
## $ roi_file <chr> "Bcu_1_roi_User_20250226101835.csv", "Bcu_1_roi_U…
## $ roi_user <chr> "User", "User"
## $ roi_input_timestamp <chr> "2025-11-05 10:22:43", "2025-02-26 10:20:12"
## $ roi_label <chr> "Basileuterus culicivorus", "Basileuterus culiciv…
## $ roi_start <dbl> 26.07112, 15.69166
## $ roi_end <dbl> 28.05989, 16.18801
## $ roi_min_freq <dbl> 2.732697, 3.150896
## $ roi_max_freq <dbl> 9.692551, 9.232058
## $ roi_type <chr> "bird - song", "bird - song"
## $ roi_label_confidence <chr> "certain", "certain"
## $ roi_is_complete <chr> "complete", "complete"
## $ roi_comment <chr> "Complete Song", "Substructure C"
## $ roi_wl <int> 1024, 1024
## $ roi_ovlp <int> 50, 70
## $ roi_sample_rate <int> 24000, 24000
## $ roi_pitch_shift <int> 1, 1
1.18 16. Exportando os cortes de audio dos templates.
Para exportar os cortes de audio dos templates, usamos a função
export_roi_cuts(). Note que os cortes de audio serão
exportados para a pasta “./templates”.
export_roi_cuts(
df_rois = df_templates, roi_cuts_path = "./templates/", overwrite = FALSE
)
list.files(path = "./templates/", pattern = "Bcu", full.names = TRUE)
1.19 Checkpoint 03
Aqui você deve decidir: se deseja seguir com o processo simplificado
(função template_matching()) execute o passo 17, ou se
deseja seguir com o processo detalhado, execute os passos 18-21.
1.20 17. Obtendo as detecções (processo simplificado)
Vamos usar o processo simplificado para obter as detecções. Esse processo é mais rápido e fácil, mas menos flexível. Ele é recomendado para projetos pequenos e para quem deseja obter rapidamente os resultados. Nesse caso vamos exportar os resultados para o arquivo “./detections/df_detecs.csv” e usar 4 núcleos para processamento paralelo, para ganhar um pouco de velocidade.
df_detecs <- template_matching(
soundscapes_path = "./soundscapes/", # local de origem das soundscapes
templates_path = "./templates/", # local de origem dos templates
ncores = 4
)
## Template metadata successfully extracted
## All files are compatible and included in the matching grid.
## Template matching finished. Detections have been returned to the R session
## Template matching finished
glimpse(df_detecs)
## Rows: 792
## Columns: 21
## $ soundscape_path <chr> "./soundscapes/W54393S25597_20201104_170000.wav"…
## $ soundscape_file <chr> "W54393S25597_20201104_170000.wav", "W54393S2559…
## $ template_path <chr> "./templates/Bcu_1_015.692-016.188s_03.151-09.23…
## $ template_file <chr> "Bcu_1_015.692-016.188s_03.151-09.232kHz_1024wl_…
## $ template_name <chr> "Bcu_1_015.692-016.188s_03.151-09.232kHz_1024wl_…
## $ template_min_freq <dbl> 3.151, 3.151, 3.151, 3.151, 3.151, 3.151, 3.151,…
## $ template_max_freq <dbl> 9.232, 9.232, 9.232, 9.232, 9.232, 9.232, 9.232,…
## $ template_start <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
## $ template_end <dbl> 0.4963333, 0.4963333, 0.4963333, 0.4963333, 0.49…
## $ detection_start <dbl> 0.5893122, 1.1401909, 2.6775271, 3.2796504, 3.90…
## $ detection_end <dbl> 1.050513, 1.601392, 3.138728, 3.740851, 4.368597…
## $ detection_wl <dbl> 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, …
## $ detection_ovlp <dbl> 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, …
## $ detection_sample_rate <int> 24000, 24000, 24000, 24000, 24000, 24000, 24000,…
## $ detection_buffer <int> 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, …
## $ detection_min_score <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
## $ detection_min_quant <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
## $ detection_top_n <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
## $ peak_index <dbl> 65, 108, 228, 275, 324, 377, 421, 472, 519, 603,…
## $ peak_score <dbl> 0.2584335, 0.2499991, 0.2765454, 0.2895299, 0.29…
## $ peak_quant <dbl> 0.916, 0.874, 0.978, 0.994, 0.997, 0.984, 0.948,…
1.21 18. Processando os metadados das soundscapes (processo detalhado).
No processo detalhado, precisamos reunir os metadados das soundscapes e dos templates separadamente. Vamos começar pelas soundscapes.
df_soundscapes <- fetch_soundscape_metadata(
soundscapes_path = "./soundscapes", # caminho para as soundscapes
recursive = TRUE, # se TRUE, lê subdiretórios de forma recursiva
ncores = 4 # quantidade de núcleos para processamento paralelo
)
glimpse(df_soundscapes)
## Rows: 12
## Columns: 6
## $ soundscape_path <chr> "./soundscapes/W54393S25597_20201104_170000.wav…
## $ soundscape_file <chr> "W54393S25597_20201104_170000.wav", "W54431S256…
## $ soundscape_duration <dbl> 59.99454, 59.99454, 59.99454, 59.99454, 59.9945…
## $ soundscape_sample_rate <int> 24000, 24000, 24000, 24000, 24000, 24000, 24000…
## $ soundscape_bitrate <int> 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16
## $ soundscape_layout <chr> "mono", "mono", "mono", "mono", "mono", "mono",…
Visualizando rapidamente os espectrogramas das soundscapes para verificar se os arquivos foram importados corretamente.
## Loading required namespace: fftw
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## ℹ The deprecated feature was likely used in the monitoraSom package.
## Please report the issue at
## <https://github.com/ConservaSom/monitoraSom/issues>.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
1.22 19. Processando os metadados dos templates (processo detalhado).
Apesar de já termos importando os templates no passo 15, vamos fazer isso novamente para garantir que ops metadados estão corretos.
df_templates <- fetch_template_metadata(
templates_path = "./templates/", recursive = TRUE
)
## Template metadata successfully extracted
glimpse(df_templates)
## Rows: 2
## Columns: 11
## $ template_path <chr> "./templates/Bcu_1_015.692-016.188s_03.151-09.232…
## $ template_file <chr> "Bcu_1_015.692-016.188s_03.151-09.232kHz_1024wl_7…
## $ template_name <chr> "Bcu_1_015.692-016.188s_03.151-09.232kHz_1024wl_7…
## $ template_label <chr> "Basileuterus culicivorus", "Basileuterus culiciv…
## $ template_start <dbl> 0, 0
## $ template_end <dbl> 0.4963333, 1.9887500
## $ template_sample_rate <int> 24000, 24000
## $ template_min_freq <dbl> 3.151, 2.733
## $ template_max_freq <dbl> 9.232, 9.693
## $ template_wl <dbl> 1024, 1024
## $ template_ovlp <dbl> 70, 50
1.23 20. Juntando os metadados das soundscapes e dos templates (processo detalhado).
O template matching pode ser custoso para grandes quantidades de
arquivos. O processo detalhado permite filtrar e organizar os dados
antes do processamento total. A função fetch_match_grid()
combina os metadados das soundscapes e templates e checa
incompatibilidades, como taxas de amostragem diferentes.
df_grid <- fetch_match_grid(
soundscape_data = df_soundscapes, template_data = df_templates
)
## All files are compatible and included in the matching grid.
glimpse(df_grid)
## Rows: 24
## Columns: 17
## $ soundscape_path <chr> "./soundscapes/W54393S25597_20201104_170000.wav…
## $ soundscape_file <chr> "W54393S25597_20201104_170000.wav", "W54393S255…
## $ soundscape_duration <dbl> 59.99454, 59.99454, 59.99454, 59.99454, 59.9945…
## $ soundscape_sample_rate <int> 24000, 24000, 24000, 24000, 24000, 24000, 24000…
## $ soundscape_bitrate <int> 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,…
## $ soundscape_layout <chr> "mono", "mono", "mono", "mono", "mono", "mono",…
## $ template_path <chr> "./templates/Bcu_1_015.692-016.188s_03.151-09.2…
## $ template_file <chr> "Bcu_1_015.692-016.188s_03.151-09.232kHz_1024wl…
## $ template_name <chr> "Bcu_1_015.692-016.188s_03.151-09.232kHz_1024wl…
## $ template_label <chr> "Basileuterus culicivorus", "Basileuterus culic…
## $ template_start <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,…
## $ template_end <dbl> 0.4963333, 1.9887500, 0.4963333, 1.9887500, 0.4…
## $ template_sample_rate <int> 24000, 24000, 24000, 24000, 24000, 24000, 24000…
## $ template_min_freq <dbl> 3.151, 2.733, 3.151, 2.733, 3.151, 2.733, 3.151…
## $ template_max_freq <dbl> 9.232, 9.693, 9.232, 9.693, 9.232, 9.693, 9.232…
## $ template_wl <dbl> 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024,…
## $ template_ovlp <dbl> 70, 50, 70, 50, 70, 50, 70, 50, 70, 50, 70, 50,…
1.24 21. Obtendo as detecções (processo detalhado)
Agora vamos rodar o template matching usando a grade produzida acima
como referência. Abaixo mostramos como rodar o template matching usando
a função run_matching() e mais alguns recursos que essa
função oferece.
run_matching(
df_grid = df_grid,
output_file = "./detections/df_detecs.csv", # arquivo com as detecções
autosave_action = "replace", # ação ao salvar o arquivo
buffer_size = "template", # buffer para evitar detecções sobrepostas
ncores = 4 # quantidade de núcleos para processamento em paralelo
)
df_detecs <- read.csv(file = "./detections/df_detecs.csv")
glimpse(df_detecs)
Dentre as opções disponíveis para o argumento
autosave_action, temos: - "replace":
sobrescreve o arquivo existente. - "append": adiciona os
resultados ao arquivo existente, mas deve ser usado com cuidado para
evitar detecções duplicadas ao importar o arquivo.
Dentre as opções disponíveis para o argumento
buffer_size, temos: - "template": buffer para
evitar detecções sobrepostas em uma região de mesma duração do template.
- Valores inteiros: define a quantidade de frames para o buffer. -
0: desliga o buffer, permitindo detecções sobrepostas em
uma região de mesma duração do template. Essa opção é recomendada
somente para projetos em que a validação não será realizada manualmente,
já que retém muitas detecções redundantes.
Outras opções de filtragem disponíveis são: - min_score:
define o score mínimo para detecção. Essa opção determina um limiar
mínimo para a detecção, excluindo todas as detecções com scores
inferiores ao valor especificado. Deve ser usada com cuidadado, pois
pode eliminar completamente soundscapes e templates sem scores acima do
limiar especificado, e assim eliminar a possibilidade de contagem
correta de FN (False Negatives) para validação a priori (ver passo 23).
- min_quant: define o quantil mínimo para detecção. Essa
opção avalia o quantil dentro de cada rodada de busca, excluindo todas
as detecções com scores inferiores ao quantil especificado. Como o
quantil é uma medida relativa, retornará sempre ao menos uma detecção
para cada rodada de busca. - top_n: define de forma
explícita a quantidade de detecções com os scores mais altos a serem
retidas. Essa opção retornará sempre a quantidade de detecções
especificada, independente do valor máximo e mínimo de scores
obtidos.
1.25 22. Caso especial: Obtendo os scores brutos.
Vamos usar a função run_matching() para fazer as buscas
na grade definida, exatamente como no passo 21, mas vamos adicionar o
argumento output = "scores" para obter os scores brutos ao
invés de ir direto para as detecções. Note que mudamos dois argumentos:
output e output_file. output
define o tipo de resultado que será retornado e output_file
define o caminho para o arquivo de saída, que agora será um arquivo RDS
em vez de CSV.
run_matching(
df_grid = df_grid,
output = "scores", # arquivo com os scores brutos
output_file = "./detections/df_scores.rds", # arquivo com os scores brutos
ncores = 4 # quantidade de núcleos para processamento em paralelo
)
## Template matching finished. Raw scores have been saved to ./detections/df_scores.rds
glimpse(df_scores)
## Rows: 72
## Columns: 20
## $ soundscape_path <chr> "./soundscapes//W54393S25597_20201104_170000.wa…
## $ soundscape_file <chr> "W54393S25597_20201104_170000.wav", "W54393S255…
## $ soundscape_duration <dbl> 59.99454, 59.99454, 59.99454, 59.99454, 59.9945…
## $ soundscape_sample_rate <int> 24000, 24000, 24000, 24000, 24000, 24000, 24000…
## $ soundscape_bitrate <int> 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,…
## $ soundscape_layout <chr> "mono", "mono", "mono", "mono", "mono", "mono",…
## $ template_path <chr> "./templates//Bcu_1_004.236-004.742s_03.151-09.…
## $ template_file <chr> "Bcu_1_004.236-004.742s_03.151-09.201kHz_1024wl…
## $ template_name <chr> "Bcu_1_004.236-004.742s_03.151-09.201kHz_1024wl…
## $ template_label <chr> "Basileuterus culicivorus", "Basileuterus culic…
## $ template_start <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,…
## $ template_end <dbl> 0.5053750, 0.4963333, 0.5098750, 0.3642500, 0.4…
## $ template_sample_rate <int> 24000, 24000, 24000, 24000, 24000, 24000, 24000…
## $ template_min_freq <dbl> 3.151, 3.151, 3.057, 2.900, 2.975, 2.878, 3.151…
## $ template_max_freq <dbl> 9.201, 9.232, 9.232, 9.764, 9.554, 9.636, 9.201…
## $ template_wl <dbl> 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024,…
## $ template_ovlp <dbl> 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,…
## $ score_sliding_window <int> 37, 36, 37, 26, 28, 28, 37, 36, 37, 26, 28, 28,…
## $ score_method <chr> "cor", "cor", "cor", "cor", "cor", "cor", "cor"…
## $ score_vec <list> [<data.frame[4684 x 2]>], [<data.frame[4684 x …
E importamos o arquivo de scores de volta para o ambiente de trabalho
usando a função readRDS() seguindo o mesmo caminho do
arquivo de saída. Ao inspecionar o objeto importado, vemos que ele retém
todas as informações da grade de busca, mas agora com os scores brutos
para cada combinação de template e soundscape armazenados como elementos
de uma lista no lugar da coluna score_vec.
df_scores <- readRDS(file = "./detections/df_scores.rds")
glimpse(df_scores)
Para entender melhor como os scores brutos são armazenados, vamos
inspecionar o primeiro elemento da lista depositada na coluna
score_vec. Note que one em um data frame normal seria um
valor único, temos outro data frame composto por 2 variáveis,
time_vec, contendo os valores de tempo em segundos para
cada frame do espectrograma da soundscape, e score_vec,
contendo os scores brutos computados para cada um desses frames.
glimpse(df_scores$score_vec[[20]])
## Rows: 4,684
## Columns: 2
## $ time_vec <dbl> 0.00000000, 0.01281113, 0.02562227, 0.03843340, 0.05124454, …
## $ score_vec <dbl> -0.1029414, -0.1029414, -0.1029414, -0.1029414, -0.1029414, …
1.26 23. Visualizando os scores brutos.
Vamos visualizar os scores brutos para poder entender melhor como as detecções foram produzidas. Notamos nessa primeira versão que precisamos de alguns ajustes para entender melhor o que está acontecendo.
plot_scores(df_scores_i = df_scores[7, ])
Agora a mesma visualização, mas com os scores ajustados para melhor visualização.
plot_scores(
df_scores_i = df_scores[7, ], ovlp = 90, wl = 1024,
dyn_range = c(-96, -48), color_scale = "inferno"
)
Mais um pouco de zoom agora para ver o pico correspondente a uma detecção mais promissora.
plot_scores(
df_scores_i = df_scores[7, ], ovlp = 70, wl = 1024,
dyn_range = c(-96, -48), color_scale = "inferno", zoom_time = c(5, 10)
)
Como as camadas de filtragem demonstradas no passo 21 ainda não foram
aplicadas nesse caso, podemos experimentar as consequencias de
aplica-las diretamente sobre os scores brutos nos proprios argumentos da
função plot_scores(). Para isso vamos remover o zoom para
ver o que está acontecendo em toda a extensão da soundscape. Nesse
primeiro exemplo vamos deixar o buffer ativo e reter as 10 detecções com
os scores mais altos.
plot_scores(
df_scores_i = df_scores[7, ], ovlp = 70, wl = 1024,
dyn_range = c(-96, -48), color_scale = "inferno",
buffer_size = "template", top_n = 6
)
Agora vamos desligar o buffer e reter somente as detecções com scores acima de 0.1. Podemos ver que nesse caso o limiar de 0.1 ainda não foi suficiente para eliminar todas as detecções que conseguimos ver que são claramente falsas.
plot_scores(
df_scores_i = df_scores[7, ], ovlp = 70, wl = 1024,
dyn_range = c(-96, -48), color_scale = "inferno",
buffer_size = 0, min_score = 0.1
)
Mas é importante lembrar que os settings selecionados aqui não funcionaão para todas as soundscapes…
plot_scores(
df_scores_i = df_scores[11, ], ovlp = 70, wl = 1024,
dyn_range = c(-96, -48), color_scale = "inferno",
buffer_size = "template", min_score = 0.1
)
A avaliação visual ajuda no ajuste inicial, mas não basta para escolher o melhor limiar. É preciso validar as detecções para definir o corte ideal de score para todo o conjunto de soundscapes. Antes prosseguir, vamos extrair as detecções desejadas a partir do arquivo de scores brutos, mas agora retendo todas as detecções, sem aplicar nenhum filtro. Note que temos 41,732 detecções no total.
df_detecs_nofilt <- fetch_score_peaks(
df_scores = df_scores,
buffer_size = 0,
output_file = "./detections/df_detecs_nofilt.csv"
)
## Detections extracted from scores
## Detections have been exported to ./detections/df_detecs_nofilt.csv
glimpse(df_detecs_nofilt)
## Rows: 41,732
## Columns: 21
## $ soundscape_path <chr> "./soundscapes//W54393S25597_20201104_170000.wav…
## $ soundscape_file <chr> "W54393S25597_20201104_170000.wav", "W54393S2559…
## $ template_path <chr> "./templates//Bcu_1_004.236-004.742s_03.151-09.2…
## $ template_file <chr> "Bcu_1_004.236-004.742s_03.151-09.201kHz_1024wl_…
## $ template_name <chr> "Bcu_1_004.236-004.742s_03.151-09.201kHz_1024wl_…
## $ template_min_freq <dbl> 3.151, 3.151, 3.151, 3.151, 3.151, 3.151, 3.151,…
## $ template_max_freq <dbl> 9.201, 9.201, 9.201, 9.201, 9.201, 9.201, 9.201,…
## $ template_start <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
## $ template_end <dbl> 0.505375, 0.505375, 0.505375, 0.505375, 0.505375…
## $ detection_start <dbl> 0.2562227, 0.3330895, 0.4740120, 0.5124454, 0.57…
## $ detection_end <dbl> 0.7174235, 0.7942903, 0.9352128, 0.9736462, 1.03…
## $ detection_wl <dbl> 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, …
## $ detection_ovlp <dbl> 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, …
## $ detection_sample_rate <int> 24000, 24000, 24000, 24000, 24000, 24000, 24000,…
## $ detection_buffer <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
## $ detection_min_score <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
## $ detection_min_quant <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
## $ detection_top_n <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
## $ peak_index <dbl> 39, 45, 56, 59, 64, 85, 88, 100, 108, 131, 139, …
## $ peak_score <dbl> 0.1690317, 0.1779760, 0.2104550, 0.2101202, 0.22…
## $ peak_quant <dbl> 0.415, 0.486, 0.746, 0.742, 0.878, 0.519, 0.521,…
1.27 Checkpoint 04
Você obteve as detecções, mas veja que ainda não sabe quais são verdadeiras ou falsas. Nesse checkpoint você poderá fazer fitragens adicionais às demonstradas no passo acima segundo os critérios do seu projeto. Nesse ponto será necessário determinar qual método de validação será usado.
1.28 23. Validando as detecções (método a priori)
O método de validação a priori é o mais completo e rápido, pois é
baseado na sobreposição temporal entre as detecções e as ROIs para a
classificação de cada detecção como verdadeira ou falsa. Esse método é
recomendado sempre que dados de segmentação estiverem disponíveis, pois
permite a contagem correta de FN (False Negatives), a partir das ROIs
que não foram alcançadas por nenhuma detecção. Nesse caso vamos usar a
função validate_by_overlap() para validar as detecções.
df_validated <- validate_by_overlap(
df_detecs = df_detecs, df_rois = df_rois, validation_user = "User"
)
## All detected species have ROIs for validation
## Validation results have been returned to the R session
glimpse(df_validated)
## Rows: 847
## Columns: 45
## $ soundscape_path <chr> "soundscapes//Bcu_1.wav", "soundscapes//Bcu_1.wa…
## $ soundscape_file <chr> "Bcu_1.wav", "Bcu_1.wav", "Bcu_1.wav", "Bcu_1.wa…
## $ template_path <chr> "./templates/Bcu_1_015.692-016.188s_03.151-09.23…
## $ template_file <chr> "Bcu_1_015.692-016.188s_03.151-09.232kHz_1024wl_…
## $ template_name <chr> "Bcu_1_015.692-016.188s_03.151-09.232kHz_1024wl_…
## $ template_min_freq <dbl> 3.151, 3.151, 3.151, 3.151, 3.151, 3.151, 3.151,…
## $ template_max_freq <dbl> 9.232, 9.232, 9.232, 9.232, 9.232, 9.232, 9.232,…
## $ template_start <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
## $ template_end <dbl> 0.4963333, 0.4963333, 0.4963333, 0.4963333, 0.49…
## $ detection_start <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
## $ detection_end <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
## $ detection_wl <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
## $ detection_ovlp <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
## $ detection_sample_rate <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
## $ detection_buffer <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
## $ detection_min_score <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
## $ detection_min_quant <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
## $ detection_top_n <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
## $ peak_index <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
## $ peak_score <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
## $ peak_quant <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
## $ species <chr> "Basileuterus culicivorus", "Basileuterus culici…
## $ detection_id <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
## $ roi_path <chr> "/home/grosa/R_repos/2025_SimposioFisicaEcologia…
## $ roi_file <chr> "Bcu_1_roi_User_20250226101835.csv", "Bcu_1_roi_…
## $ roi_user <chr> "User", "User", "User", "User", "User", "User", …
## $ roi_input_timestamp <chr> "2025-02-26 10:19:57", "2025-02-26 10:20:12", "2…
## $ roi_label <chr> "Basileuterus culicivorus", "Basileuterus culici…
## $ roi_start <dbl> 4.236420, 15.691662, 27.506793, 3.794958, 15.259…
## $ roi_end <dbl> 4.741796, 16.188014, 28.016681, 4.189475, 15.694…
## $ roi_min_freq <dbl> 3.150896, 3.150896, 3.057099, 3.659274, 3.561569…
## $ roi_max_freq <dbl> 9.200792, 9.232058, 9.232058, 5.629660, 5.743649…
## $ roi_type <chr> "bird - song", "bird - song", "bird - song", "bi…
## $ roi_label_confidence <chr> "certain", "certain", "certain", "certain", "cer…
## $ roi_is_complete <chr> "complete", "complete", "complete", "complete", …
## $ roi_comment <chr> "Substructure C", "Substructure C", "Substructur…
## $ roi_wl <int> 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, …
## $ roi_ovlp <int> 70, 70, 70, 70, 70, 70, 70, 70, 70, 50, 50, 70, …
## $ roi_sample_rate <int> 24000, 24000, 24000, 24000, 24000, 24000, 24000,…
## $ roi_pitch_shift <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, …
## $ roi_id <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 1…
## $ validation_user <chr> "User", "User", "User", "User", "User", "User", …
## $ validation_time <chr> "2025-11-05 18:17:13", "2025-11-05 18:17:13", "2…
## $ validation <chr> "FN", "FN", "FN", "FN", "FN", "FN", "FN", "FN", …
## $ validation_note <chr> "no detections to intersect with", "no detection…
1.29 24. Checagens sanitárias das detecções validadas.
Inspecionando o objeto com os resultados da validação, podemos ver
todas as variáveis da tabela de detecções, mas agora também agregamos
dados sobre as ROIs para os casos de correspondência, revelando todos os
pares de detecção x ROI, bem como as ROIs que não foram alcançadas por
nenhuma detecção. O status de cada detecção é armazenado na coluna
validation, que pode ter os valores TP
(verdadeiro positivo ou detecção confirmada ), FP (falso
positivo ou detecção falsa) ou FN (falso negativo ou
detecção não alcançada). Vejamos as contagens dessa classificação para
cada template.
table(df_validated$validation, df_validated$template_name)
##
## Bcu_1_015.692-016.188s_03.151-09.232kHz_1024wl_70ovlp_Basileuterus culicivorus.wav
## FN 22
## FP 591
## TP 48
##
## Bcu_1_026.071-028.060s_02.733-09.693kHz_1024wl_50ovlp_Basileuterus culicivorus.wav
## FN 33
## FP 116
## TP 37
Mas antes disso, vamos relembrar a quantidade de detecções que obtivemos com cada método. A versão não filtrada tem 41,732 detecções, enquanto a versão filtrada tem 4,363 detecções..
nrow(df_detecs)
## [1] 792
nrow(df_detecs_nofilt)
## [1] 41732
É importante ressaltar que tanto df_detecs, sua versão
não filtrada, quanto df_validated, reunem as detecções e
detecções validades de todos os templates de forma agregada, apesar dos
processos serem computados separadamente para cada template.
Vamos comparar o desempenho do método de validação a priori em diferentes cenários. Ao aplicar a validação na versão filtrada das detecções, temos um processo rápido devido à menor quantidade de detecções. Já na versão não filtrada, o número de detecções é consideravelmente maior, e, ainda assim, o tempo de processamento permaneceu eficiente. Isso mostra que mesmo trabalhando com grandes volumes de dados, a validação automática ocorre de forma muito rápida. Portanto, além de permitir a validação da totalidade das detecções, a abordagem automatizada elimina a necessidade de checagem manual, sendo muito mais ágil e prática do que o método manual (a posteriori), apresentado a seguir. Por isso, nós, os desenvolvedores, recomendamos o uso do método de validação a priori sempre que possível.
# Cronometrando o tempo de processamento da validação das detecs filtradas
system.time({
validate_by_overlap(
df_detecs = df_detecs, df_rois = df_rois, validation_user = "User"
)
})
## All detected species have ROIs for validation
## Validation results have been returned to the R session
## user system elapsed
## 0.055 0.000 0.055
# Cronometrando o tempo de processamento da validação das detecs não filtradas
system.time({
validate_by_overlap(
df_detecs = df_detecs_nofilt, df_rois = df_rois, validation_user = "User"
)
})
## All detected species have ROIs for validation
## Validation results have been returned to the R session
## user system elapsed
## 0.380 0.001 0.382
1.30 25. Validando as detecções (método a posteriori)
Quando não temos dados de segmentação manual, podemos validar as detecções manualmente. Nesse caso vamos usar o app de validação manual do monitoraSom. Mas antes de prosseguir, vamos fazer uma cópia da tabela de detecções para não perdermos os dados originais.
file.copy(
from = "./detections/df_detecs.csv",
to = "./detections/df_detecs_aposteriori.csv",
overwrite = FALSE # para evitar sobrescrever a cópia, caso já exista
)
Agora vamos usar o app de validação manual para validar as detecções.
launch_validation_app(
project_path = ".", validation_user = "User",
templates_path = "./templates/", soundscapes_path = "./soundscapes/",
input_path = "./detections/df_detecs_aposteriori.csv",
output_path = "./detections/df_detecs_aposteriori.csv",
dyn_range_templ = c(-78, -30), dyn_range_detec = c(-78, -30), wl = 1024,
ovlp = 70, time_guide_interval = 0, freq_guide_interval = 0,
overwrite = TRUE
)
1.31 26. Importando e inspecionando os resultados da validação a posteriori.
Agora vamos importar o arquivo de detecções validadas de volta para o
ambiente de trabalho usando a função read.csv() seguindo o
mesmo caminho do arquivo de saída.
df_detecs_aposteriori <- read.csv(
file = "./detections/df_detecs_aposteriori.csv"
)
glimpse(df_detecs_aposteriori)
## Rows: 732
## Columns: 21
## $ soundscape_path <chr> "./soundscapes/W54393S25597_20201104_170000.wav"…
## $ soundscape_file <chr> "W54393S25597_20201104_170000.wav", "W54393S2559…
## $ template_path <chr> "./templates/Bcu_1_015.692-016.188s_03.151-09.23…
## $ template_file <chr> "Bcu_1_015.692-016.188s_03.151-09.232kHz_1024wl_…
## $ template_name <chr> "Bcu_1_015.692-016.188s_03.151-09.232kHz_1024wl_…
## $ template_min_freq <dbl> 3.151, 3.151, 3.151, 3.151, 3.151, 3.151, 3.151,…
## $ template_max_freq <dbl> 9.232, 9.232, 9.232, 9.232, 9.232, 9.232, 9.232,…
## $ template_start <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
## $ template_end <dbl> 0.4963333, 0.4963333, 0.4963333, 0.4963333, 0.49…
## $ detection_start <dbl> 0.5893122, 1.1401909, 2.6775271, 3.2796504, 3.90…
## $ detection_end <dbl> 1.050513, 1.601392, 3.138728, 3.740851, 4.368597…
## $ detection_wl <dbl> 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, …
## $ detection_ovlp <dbl> 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, …
## $ detection_sample_rate <int> 24000, 24000, 24000, 24000, 24000, 24000, 24000,…
## $ detection_buffer <int> 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, …
## $ detection_min_score <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
## $ detection_min_quant <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
## $ detection_top_n <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
## $ peak_index <dbl> 65, 108, 228, 275, 324, 377, 421, 472, 519, 603,…
## $ peak_score <dbl> 0.2584335, 0.2499991, 0.2765454, 0.2895299, 0.29…
## $ peak_quant <dbl> 0.916, 0.874, 0.978, 0.994, 0.997, 0.984, 0.948,…
NV = not validated
table(
df_detecs_aposteriori$validation,
df_detecs_aposteriori$template_name
)
1.32 27. Comparando os resultados das validações a priori e a posteriori.
Vamos comparar os resultados das validações a priori e a posteriori.
df_rois %>%
filter(!grepl("Bcu", soundscape_file)) %>%
nrow()
nrow(df_detecs_aposteriori)
table(df_detecs_aposteriori$validation, df_detecs_aposteriori$template_name)
1.33 28. Diagnósticos de performance.
Quando trabalhamos com detecção automática, especialmente utilizando métodos como template matching, é fundamental avaliar métricas de performance como a precision (precisão) e recall ou sensitivity (sensibilidade). A precisão quantifica quantas das detecções obtidas estão corretas, enquanto o recall mede quantas das ocorrências dos sinais alvo foram de fato detectadas.
Essas métricas geralmente apresentam uma relação de toma-lá-dá-cá: aumentar o limiar para considerar detecções verdadeiras pode aumentar a precisão (menos FP), mas também pode diminuir o recall (mais FN). Por outro lado, abaixar o limiar pode aumentar o recall mas reduzir a precisão. Portanto, avaliar os resultados em termos de precision e recall é essencial para escolher o limiar ideal do template matching para seu objetivo, seja ele minimizar falsos positivos, maximizar a recuperação de eventos ou buscar um equilíbrio entre ambos.
A função diagnostic_validations() produz uma lista com
os diagnósticos de performance para cada template.
ls_val_apriori <- diagnostic_validations(
df_validated = df_validated, pos_prob = 0.90, val_a_priori = TRUE
)
## Validation diagnostics completed successfully.
# Separando os resultados para cada template
res_template1 <- ls_val_apriori[[1]]
res_template2 <- ls_val_apriori[[2]]
Inspecionando os diagnósticos de performance para cada template. Os dataframes contém todas as métricas de performance para cada template em função dos limiares de score avaliados.
res_template1$diagnostics %>% glimpse()
## Rows: 639
## Columns: 12
## $ template_name <chr> "Bcu_1_015.692-016.188s_03.151-09.232kHz_1024wl_70ovlp_B…
## $ peak_score <dbl> 0.6027716, 0.4985262, 0.4962222, 0.4902171, 0.4830211, 0…
## $ tp <dbl> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1…
## $ fp <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,…
## $ tn <int> 591, 591, 591, 591, 591, 591, 591, 591, 591, 591, 591, 5…
## $ fn <int> 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, …
## $ precision <dbl> 1.0000000, 1.0000000, 1.0000000, 1.0000000, 1.0000000, 1…
## $ recall <dbl> 0.01428571, 0.02857143, 0.04285714, 0.05714286, 0.071428…
## $ sensitivity <dbl> 0.01428571, 0.02857143, 0.04285714, 0.05714286, 0.071428…
## $ specificity <dbl> 1.000000, 1.000000, 1.000000, 1.000000, 1.000000, 1.0000…
## $ F1_score <dbl> 0.02816901, 0.05555556, 0.08219178, 0.10810811, 0.133333…
## $ selected <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, …
res_template2$diagnostics %>% glimpse()
## Rows: 153
## Columns: 12
## $ template_name <chr> "Bcu_1_026.071-028.060s_02.733-09.693kHz_1024wl_50ovlp_B…
## $ peak_score <dbl> 0.5992908, 0.5977625, 0.5824681, 0.5347159, 0.5290634, 0…
## $ tp <dbl> 1, 2, 3, 4, 4, 5, 6, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,…
## $ fp <dbl> 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,…
## $ tn <int> 116, 116, 116, 116, 115, 115, 115, 114, 114, 114, 114, 1…
## $ fn <int> 69, 68, 67, 66, 66, 65, 64, 64, 63, 62, 61, 60, 59, 58, …
## $ precision <dbl> 1.0000000, 1.0000000, 1.0000000, 1.0000000, 0.8000000, 0…
## $ recall <dbl> 0.01428571, 0.02857143, 0.04285714, 0.05714286, 0.057142…
## $ sensitivity <dbl> 0.01428571, 0.02857143, 0.04285714, 0.05714286, 0.057142…
## $ specificity <dbl> 1.0000000, 1.0000000, 1.0000000, 1.0000000, 0.9913793, 0…
## $ F1_score <dbl> 0.02816901, 0.05555556, 0.08219178, 0.10810811, 0.106666…
## $ selected <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, …
Nos resultados de cada templates também temos disponíveis os gráficos de métricas de performance em função dos limiares de score avaliados. Na primeira coluna temos os dados do primeiro template, aquele composto somete pela parte final do canto, enquanto na segunda coluna temos os dados do segundo template, aquele composto pelo canto completo. Na primeira linha temos os gráficos dos modelos binomiais, nos quais definimos o score com a probabilidade posterior de 95% da detecção ser verdadeira. Na segunda linha mostramos os gráficos de precisão e recall em função dos limiares de score avaliados. Em todos os casos as linhas vermelhas representam os níveis de score selecionados para cada template
cowplot::plot_grid(
res_template1$mod_plot, res_template2$mod_plot,
res_template1$precrec_plot, res_template2$precrec_plot,
ncol = 2
)
1.34 29. Obtendo o conjunto final de detecções.
template1_score <- ls_val_apriori[[1]]$score_cut
template2_score <- ls_val_apriori[[2]]$score_cut
template1_name <- ls_val_apriori[[1]]$diagnostics$template_name[1]
template2_name <- ls_val_apriori[[2]]$diagnostics$template_name[1]
df_detecs_final_1 <- df_detecs %>%
filter(
template_name == template1_name & peak_score >= template1_score
) %>%
glimpse()
## Rows: 13
## Columns: 21
## $ soundscape_path <chr> "./soundscapes/W54431S25613_20191104_154000.wav"…
## $ soundscape_file <chr> "W54431S25613_20191104_154000.wav", "W54431S2561…
## $ template_path <chr> "./templates/Bcu_1_015.692-016.188s_03.151-09.23…
## $ template_file <chr> "Bcu_1_015.692-016.188s_03.151-09.232kHz_1024wl_…
## $ template_name <chr> "Bcu_1_015.692-016.188s_03.151-09.232kHz_1024wl_…
## $ template_min_freq <dbl> 3.151, 3.151, 3.151, 3.151, 3.151, 3.151, 3.151,…
## $ template_max_freq <dbl> 9.232, 9.232, 9.232, 9.232, 9.232, 9.232, 9.232,…
## $ template_start <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
## $ template_end <dbl> 0.4963333, 0.4963333, 0.4963333, 0.4963333, 0.49…
## $ detection_start <dbl> 7.597003, 22.739763, 33.680472, 46.465984, 10.03…
## $ detection_end <dbl> 8.058203, 23.200964, 34.141673, 46.927185, 10.49…
## $ detection_wl <dbl> 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, …
## $ detection_ovlp <dbl> 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, …
## $ detection_sample_rate <int> 24000, 24000, 24000, 24000, 24000, 24000, 24000,…
## $ detection_buffer <int> 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, …
## $ detection_min_score <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
## $ detection_min_quant <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
## $ detection_top_n <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
## $ peak_index <dbl> 612, 1794, 2648, 3646, 802, 2297, 1983, 2349, 33…
## $ peak_score <dbl> 0.4830211, 0.4985262, 0.4731373, 0.4962222, 0.44…
## $ peak_quant <dbl> 0.999, 1.000, 0.999, 1.000, 1.000, 1.000, 1.000,…
df_detecs_final_2 <- df_detecs %>%
filter(
template_name == template2_name & peak_score >= template2_score
) %>%
glimpse()
## Rows: 10
## Columns: 21
## $ soundscape_path <chr> "./soundscapes/W54448S25622_20191101_073000.wav"…
## $ soundscape_file <chr> "W54448S25622_20191101_073000.wav", "W54448S2562…
## $ template_path <chr> "./templates/Bcu_1_026.071-028.060s_02.733-09.69…
## $ template_file <chr> "Bcu_1_026.071-028.060s_02.733-09.693kHz_1024wl_…
## $ template_name <chr> "Bcu_1_026.071-028.060s_02.733-09.693kHz_1024wl_…
## $ template_min_freq <dbl> 2.733, 2.733, 2.733, 2.733, 2.733, 2.733, 2.733,…
## $ template_max_freq <dbl> 9.693, 9.693, 9.693, 9.693, 9.693, 9.693, 9.693,…
## $ template_start <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
## $ template_end <dbl> 1.98875, 1.98875, 1.98875, 1.98875, 1.98875, 1.9…
## $ detection_start <dbl> 8.006389, 19.407487, 28.801650, 40.437602, 43.34…
## $ detection_end <dbl> 9.970623, 21.371721, 30.765884, 42.401836, 45.30…
## $ detection_wl <dbl> 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, …
## $ detection_ovlp <dbl> 50, 50, 50, 50, 50, 50, 50, 50, 50, 50
## $ detection_sample_rate <int> 24000, 24000, 24000, 24000, 24000, 24000, 24000,…
## $ detection_buffer <int> 92, 92, 92, 92, 92, 92, 92, 92, 92, 92
## $ detection_min_score <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA
## $ detection_min_quant <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA
## $ detection_top_n <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA
## $ peak_index <dbl> 422, 956, 1396, 1941, 2077, 2339, 2521, 1979, 28…
## $ peak_score <dbl> 0.5977625, 0.5992908, 0.5824681, 0.5191764, 0.53…
## $ peak_quant <dbl> 1.000, 1.000, 0.998, 0.980, 0.989, 0.972, 0.987,…
detection_plots1 <- df_detecs_final_1 %>%
split(., seq(nrow(.))) %>%
purrr::map(., ~ {
wav <- tuneR::readWave(
filename = .x$soundscape_path, from = .x$detection_start, to = .x$detection_end, units = "seconds"
)
res <- fast_spectro(
rec = wav, f = wav@samp.rate, wl = 512, ovlp = 90,
dyn_range = c(-102, -42), color_scale = "greyscale 1",
freq_guide_interval = 0, time_guide_interval = 0,
zoom_freq = c(
.x$template_min_freq,
.x$template_max_freq
)
) +
theme_bw() +
theme(legend.position = "none")
return(res)
}, .progress = TRUE)
cowplot::plot_grid(
detection_plots1[[1]], detection_plots1[[2]],
detection_plots1[[3]], detection_plots1[[4]],
detection_plots1[[5]], detection_plots1[[6]],
detection_plots1[[7]], detection_plots1[[8]],
detection_plots1[[9]], detection_plots1[[10]],
detection_plots1[[11]], detection_plots1[[12]],
ncol = 4
)
detection_plots2 <- df_detecs_final_2 %>%
split(., seq(nrow(.))) %>%
purrr::map(., ~ {
wav <- tuneR::readWave(
filename = .x$soundscape_path, from = .x$detection_start, to = .x$detection_end, units = "seconds"
)
res <- fast_spectro(
rec = wav, f = wav@samp.rate, wl = 1024, ovlp = 70,
dyn_range = c(-102, -42), color_scale = "greyscale 1",
freq_guide_interval = 0, time_guide_interval = 0,
zoom_freq = c(
.x$template_min_freq,
.x$template_max_freq
)
) +
theme_bw() +
theme(legend.position = "none")
return(res)
}, .progress = TRUE)
cowplot::plot_grid(
detection_plots2[[1]], detection_plots2[[2]],
detection_plots2[[3]], detection_plots2[[4]],
detection_plots2[[5]], detection_plots2[[6]],
detection_plots2[[7]], detection_plots2[[8]],
detection_plots2[[9]], detection_plots2[[10]],
ncol = 5
)
1.35 30. Transformando as detecções finais em tabelas de ROIs
dir.create("./final_detecs", showWarnings = FALSE)
df_final <- rbind(df_detecs_final_1, df_detecs_final_2) %>% glimpse()
df_rois_final <- detecs_to_rois(
df_detecs = df_final, username = "User",
output_path = "./final_detecs/"
)